package com.xiaotu.code.util;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;

import org.apache.commons.io.FileUtils;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

/**
 * 针对图片的处理工具类.
 * 
 * @author chenxiangrong
 * 
 */
@SuppressWarnings("restriction")
public class ImageUtil {
	/**
	 * 生成图片的缩略图.
	 * 
	 * @param filePath
	 *            (文件路径)
	 * @param fileName
	 *            (缩略图的文件名)
	 * @param outputWidth
	 *            (缩略图的宽度)
	 * @param outputHeight
	 *            (缩略图的高度)
	 * @param proportion
	 *            (是否按比例缩放)
	 * @throws IOException
	 */
	public static String compressPicByProportion(String filePath,
			String fileName, int outputWidth, int outputHeight,
			boolean proportion) throws IOException {
		// 获得源文件
		File file = new File(filePath);
		if (file.exists()) {
			Image img = ImageIO.read(file);

			int newWidth;
			int newHeight;
			// 判断是否是等比缩放
			if (proportion == true) {
				// 为等比缩放计算输出的图片宽度及高度
				double rate1 = ((double) img.getWidth(null))
						/ (double) outputWidth + 0.1;
				double rate2 = ((double) img.getHeight(null))
						/ (double) outputHeight + 0.1;
				// 根据缩放比率大的进行缩放控制
				double rate = rate1 > rate2 ? rate1 : rate2;
				newWidth = (int) (((double) img.getWidth(null)) / rate);
				newHeight = (int) (((double) img.getHeight(null)) / rate);
			} else {
				newWidth = outputWidth; // 输出的图片宽度
				newHeight = outputHeight; // 输出的图片高度
			}
			BufferedImage tag = new BufferedImage((int) newWidth,
					(int) newHeight, BufferedImage.TYPE_INT_RGB);

			/*
			 * Image.SCALE_SMOOTH 的缩略算法 生成缩略图片的平滑度的 优先级比速度高 生成的图片质量比较好 但速度慢
			 */
			tag.getGraphics().drawImage(
					img.getScaledInstance(newWidth, newHeight,
							Image.SCALE_SMOOTH), 0, 0, null);
			FileOutputStream out = new FileOutputStream(FileUtil
					.getFileName(filePath)
					+ fileName);
			// JPEGImageEncoder可适用于其他图片类型的转换
			JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
			encoder.encode(tag);
			out.close();
			return filePath + fileName;
		} else
			return "";
	}

	/**
	 * 按策略生成图片缩略图(1：原图的width<limitWidth,height<limitHeight，不压缩；2：原图的其中一个小于limit,
	 * 另一个大于limit，两边按照大于边/limit的比例缩放；3:两边均大于，取大比列缩放；不够的地方补白填充.).
	 * 
	 * @param filePath
	 *            (文件路径)
	 * @param outPutPath
	 *            (缩略图输出路径)
	 * @param fileName
	 *            (缩略图文件名)
	 * @param limitWith
	 *            (限宽)
	 * @param limitHeight
	 *            (限高)
	 * @return
	 * @throws IOException
	 */
	public static void compressPicByStrategy(String filePath,
			String outPutPath, String fileName, int limitWidth, int limitHeight)
			throws IOException {
		// 创建临时文件
		int pox = filePath.lastIndexOf(".");
		String ext = filePath.substring(pox + 1);
		String pre = filePath.substring(0, pox);
		String tmp = pre + "_tmp." + ext;
		// 读取源图像
		Image img = ImageIO.read(new File(filePath));
		int originalWidth = img.getWidth(null);// 原图宽度
		int originalHeight = img.getHeight(null);// 原图高度
		if (originalWidth > limitWidth || originalHeight > limitHeight) {
			int[] newWH = getNewWAndH(originalWidth, originalHeight,
					limitWidth, limitHeight);
			originalWidth = newWH[0];
			originalHeight = newWH[1];
			// 长、高按规则压缩，生成图片.
			BufferedImage bi = new BufferedImage(originalWidth, originalHeight,
					BufferedImage.TYPE_INT_RGB);
			Graphics2D g2 = (Graphics2D) bi.getGraphics();
			g2.setBackground(Color.WHITE);
			g2.clearRect(0, 0, originalWidth, originalHeight);
			g2.drawImage(img, 0, 0, originalWidth, originalHeight, null);
			// ImageIO.write(bi, "JPEG",new File(tmp));
			FileOutputStream newimage = new FileOutputStream(new File(tmp)); // 输出到文件流
			JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(newimage);
			JPEGEncodeParam jep = JPEGCodec.getDefaultJPEGEncodeParam(bi);
			/* 压缩质量 */
			jep.setQuality(1.0f, true);
			encoder.encode(bi, jep);
			// encoder.encode(tag); //近JPEG编码
			newimage.close();
		} else {
			FileUtils.copyFile(new File(filePath), new File(tmp));
		}// 将压缩图片填充生成新图片.
		Image img1 = ImageIO.read(new File(tmp));
		int width1 = img1.getWidth(null); // 得到源图宽
		int height1 = img1.getHeight(null); // 得到源图长

		BufferedImage bi1 = new BufferedImage(limitWidth, limitHeight,
				BufferedImage.TYPE_INT_RGB);
		Graphics2D g21 = (Graphics2D) bi1.getGraphics();
		g21.setBackground(Color.WHITE);
		g21.clearRect(0, 0, limitWidth, limitHeight);
		int pX = limitWidth - width1 > 0 ? (limitHeight - width1) / 2 : 0;
		int pY = limitWidth - height1 > 0 ? (limitHeight - height1) / 2 : 0;

		g21.drawImage(img1, pX, pY, null);
		// ImageIO.write(bi1, "JPEG", new File(imgSrc));
		FileOutputStream newimage1 = new FileOutputStream(new File(outPutPath)); // 输出到文件流
		JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(newimage1);
		JPEGEncodeParam jep = JPEGCodec.getDefaultJPEGEncodeParam(bi1);
		/* 压缩质量 */
		jep.setQuality(1.0f, true);
		encoder.encode(bi1, jep);
		newimage1.close();

		FileUtils.forceDelete(new File(tmp));
	}

	/**
	 * 获取新的宽高.
	 * 
	 * @param originalWidth
	 * @param originalHeight
	 * @param limitWidth
	 * @param limitHeight
	 * @return
	 */
	public static int[] getNewWAndH(int originalWidth, int originalHeight,
			int limitWidth, int limitHeight) {
		float newW = 0;
		float newH = 0;
		float scale = 0;
		if (originalWidth > limitWidth && originalHeight < limitHeight) {
			scale = new Integer(originalWidth).floatValue()
					/ new Integer(limitWidth).floatValue();
			newH = originalHeight / scale;
			newW = limitWidth;
		} else if (originalWidth < limitWidth && originalHeight > limitHeight) {
			scale = new Integer(originalHeight).floatValue()
					/ new Integer(limitHeight).floatValue();
			newW = originalWidth / scale;
			newH = limitHeight;
		} else if (originalWidth > limitWidth && originalHeight > limitHeight) {
			float hbl = new Integer(originalHeight).floatValue()
					/ new Integer(limitHeight).floatValue();
			float wbl = new Integer(originalWidth).floatValue()
					/ new Integer(limitWidth).floatValue();
			scale = hbl > wbl ? hbl : wbl;
			newW = originalWidth / scale;
			newH = originalHeight / scale;
		} else {
			newW = originalWidth;
			newH = originalHeight;
		}

		int[] newWH = { Math.round(newW), Math.round(newH) };
		return newWH;
	}

	/**
	 * 压缩fileSize.
	 * 
	 * @param filePath
	 *            (文件路径)
	 * @param outPutPath
	 *            (压缩后的输出路径)
	 * @throws IOException
	 */
	@SuppressWarnings("static-access")
	public static void compressPic(String filePath, String outPutPath)
			throws IOException {
		File file = null;
		BufferedImage src = null;
		FileOutputStream out = null;
		ImageWriter imgWrier;
		ImageWriteParam imgWriteParams;

		// 指定写图片的方式为 jpg
		imgWrier = ImageIO.getImageWritersByFormatName("jpg").next();
		imgWriteParams = new javax.imageio.plugins.jpeg.JPEGImageWriteParam(
				null);
		// 要使用压缩，必须指定压缩方式为MODE_EXPLICIT
		imgWriteParams.setCompressionMode(imgWriteParams.MODE_EXPLICIT);
		// 这里指定压缩的程度，参数qality是取值0~1范围内，
		imgWriteParams.setCompressionQuality((float) 0.1);
		imgWriteParams.setProgressiveMode(imgWriteParams.MODE_DISABLED);
		ColorModel colorModel = ColorModel.getRGBdefault();
		// 指定压缩时使用的色彩模式
		imgWriteParams.setDestinationType(new javax.imageio.ImageTypeSpecifier(
				colorModel, colorModel.createCompatibleSampleModel(16, 16)));

		file = new File(filePath);
		src = ImageIO.read(file);
		out = new FileOutputStream(outPutPath);

		imgWrier.reset();
		// 必须先指定 out值，才能调用write方法, ImageOutputStream可以通过任何 OutputStream构造
		imgWrier.setOutput(ImageIO.createImageOutputStream(out));
		// 调用write方法，就可以向输入流写图片
		imgWrier.write(null, new IIOImage(src, null, null), imgWriteParams);
		out.flush();
		out.close();

	}
}